#include "../include/MainFrame.h"
#include "MySql/MySqlEmbeddedWrapper.cpp"

//(*InternalHeaders(CMainFrame)
#include <wx/xrc/xmlres.h>
//*)

//(*IdInit(CMainFrame)
//*)

BEGIN_EVENT_TABLE(CMainFrame,wxFrame)
	//(*EventTable(CMainFrame)
	//*)
END_EVENT_TABLE()

CMainFrame::CMainFrame(wxWindow* parent)
{
    ///(* seed the random number generator
    srand( (int)time);
    ///*)

    ///(* display splash screen
//#ifndef _DEBUG
    wxString Version = wxString::Format(_("Version %i.%i.%i"), AutoVersion::MAJOR, AutoVersion::MINOR, AutoVersion::BUILD);
    wxString Revision = wxString::Format(_("Revision %i"), AutoVersion::REVISION);
    m_pSplash = new CSplashScreen(this, 5000, (mmImageDir + "splash.png"), &Version, &Revision);
    m_pSplash->SetStatusMsg(_("Initializing...") );
    m_pSplash->Start();
//#endif
    ///*)

	//(*Initialize(CMainFrame)
	wxXmlResource::Get()->LoadObject(this,parent,_T("CMainFrame"),_T("wxFrame"));
	StatusBar1 = (wxStatusBar*)FindWindow(XRCID("idStatusBar"));

	Connect(XRCID("idMenuFileExit"),wxEVT_COMMAND_MENU_SELECTED,(wxObjectEventFunction)&CMainFrame::OnMenuFileExitSelected);
	Connect(XRCID("idMenuEditOptions"),wxEVT_COMMAND_MENU_SELECTED,(wxObjectEventFunction)&CMainFrame::OnMenuEditOptionsSelected);
	Connect(XRCID("idMenuAccountsNew"),wxEVT_COMMAND_MENU_SELECTED,(wxObjectEventFunction)&CMainFrame::OnMenuAccountsNewSelected);
	Connect(XRCID("idMenuAccountsDelete"),wxEVT_COMMAND_MENU_SELECTED,(wxObjectEventFunction)&CMainFrame::OnMenuAccountsDeleteSelected);
	Connect(XRCID("idMenuHelpAbout"),wxEVT_COMMAND_MENU_SELECTED,(wxObjectEventFunction)&CMainFrame::OnMenuHelpAboutSelected);
	Connect(XRCID("idMenuHelpLicense"),wxEVT_COMMAND_MENU_SELECTED,(wxObjectEventFunction)&CMainFrame::OnMenuHelpLicenseSelected);
	Connect(XRCID("idMenuHelpHelp"),wxEVT_COMMAND_MENU_SELECTED,(wxObjectEventFunction)&CMainFrame::OnMenuHelpHelpSelected);
	Connect(wxID_ANY,wxEVT_CLOSE_WINDOW,(wxObjectEventFunction)&CMainFrame::OnClose);
	//*)

    // set the text for the status bar
    StatusBar->SetStatusText( (wxDateTime::Today() ).Format("%A\n%B %d, %Y"), 2);

    ///(* initialize settings and configuration
//#ifndef _DEBUG
    m_pSplash->SetStatusMsg(_("Loading Settings...") );
//#endif

    m_pData = new CData();

    mm::g_pOptions = new mm::COptions();
    mm::g_pOptions->Initialize();
    mm::g_pOptions->LoadOptions();
    this->SetOwnBackgroundColour(mm::g_pOptions->COLORS.MainBGColor);
    ///*)

    ///(* accept license
    if (mm::g_pOptions->GLOBAL.FirstRun)
    {
        CLicenseDlg Dlg(this, false);
        if (Dlg.ShowModal() == wxID_CANCEL)
        {
            this->Close(true);
            return;
        }
    }
    ///*)

    ///(* start the MySQL server and connect to it
//#ifndef _DEBUG
    m_pSplash->SetStatusMsg(_("Initializing Database...") );
//#endif
    m_pMySql = new CMySqlWrapper();
    wxArrayString Groups;
    for (int x = 0; x < 3, x++)
        Groups.Add(mmSqlGroups[x] );
    if (!m_pMySql->StartConnection(mmProgName, mmIniFile, Groups) )
    {
        wxString msg = _("Could not initialize database -\n") + m_pMySql->GetLastError();
        mmFatalErrorDlg(this, msg);
        return;
    }
    ///*)

    ///(* create shared database if first run
    if (mm::g_pOptions->GLOBAL.FirstRun)
    {
        if (!mm::CreateSharedDatabase(m_pMySql) )
        {
            mmFatalErrorDlg(this, m_pMySql->GetLastError() );
            return;
        }
    }
    ///*)

    ///(* load plugins
//#ifndef _DEBUG
    m_pSplash->SetStatusMsg(_("Loading Plugins...") );
//#endif
    m_PluginManager.Initialize(this, m_pMySql);
    if (m_PluginManager.LoadAllPlugins() <= 0)
    {
        mmFatalErrorDlg(this, _("No available account plugins!") );
        return;
    }
    ///*)

    ///(* log in to user account
//#ifndef _DEBUG
    m_pSplash->SetStatusMsg(_("Logging In...") );
//#endif
    // if first run then setup first user
    if (mm::g_pOptions->GLOBAL.FirstRun)
    {
        bool RememberMe = false;
        SUserInfo UI;
        do
        {
            if (!m_Users.GetNewUserInfo(this, UI, RememberMe, true) )
            {
                // user clicked "cancel"
                Close();
                return;
            }
        } while (m_Users.CheckIfUserNameExists(UI.UserName) );

        if (!m_Users.SaveUser(UI, true, true) )
        {
            // could not create user
            this->Close(true);
            return;
        }
        if (RememberMe)
        {
            mm::g_pOptions->LOGIN.DefaultUserName = UI.UserName;
            mm::g_pOptions->LOGIN.DefaultPassword = UI.Password;
        }
        if (!m_Users.LogInUser(UI, false) )
        {
            // could not log in user
            Close(true);
            return;
        }
    }
    else
    {
        // user log in
        if (!m_Users.LogInUser(UI) )
        {
            Close(true);
            return;
        }
    }
    m_pStatusBar->SetStatusText(wxString::Format(_("Welcome, %s"), UI.FirstName), 1);
    ///*)

    ///(* load data
//#ifndef _DEBUG
    m_pSplash->SetStatusMsg(_("Loading Data...") );
//#endif
    if (!LoadData() )
    {
        mmErrorDlg(this, _("Failed to load Data") );
    }
    ///*)

    ///(* load accounts
//#ifndef _DEBUG
    m_pSplash->SetStatusMsg(_("Loading Accounts...") );
//#endif
    m_pAccountManager = new CAccountManager(this, wxNewId(), m_pMySql);
    if (m_pAccountManager->LoadAccounts() == 0)
    {
        m_pAccountManager->CreateFirstAccount(m_CurrentUser);
    }
    ///*)

    ///(* add the info bar and account manager to the sizer
    m_pInfoBar = new wxInfoBar(this);
    wxSizer* Sizer = GetSizer();
    Sizer->Add(m_pInfoBar, wxSizerFlags(0).Expand() );
    Sizer->Add(m_pAccountManger, wxSizerFlags(1).Expand() );
    SetSizerAndFit(Sizer);
    ///*)

    ///(* dismiss splash screen and show main window
//#ifndef _DEBUG
    bool IsOkToRun = false;
    do
    {
    } while (!m_pSplash->IsFinished() )
    m_pSplash->Stop();
    delete m_pSplash;
//#endif
    ///*)

	// make full screen
	Maximize(true);

    mm::g_pOptions->GLOBAL.FirstRun = false;
}

CMainFrame::~CMainFrame()
{
	//(*Destroy(CMainFrame)
	//*)
}

CAccountPlugin* CMainFrame::GetAccountPlugin(const wxString& PluginName)
{
    return (CAccountPlugin*)m_pPluginManager->GetPluginByName(AccountType);

}

bool CMainFrame::LoadData()
{
    wxString Query;

    // load data types
    Query = wxString::Format("SELECT * FROM %s.tab_Data", mmSharedDBName);
    if (m_pMySql->RunQuery(Query) )
    {
        MYSQL_ROW row;
        while (row = m_pMySql->GetNextRowFromResultSet() )
        {
            if (row[1] != NULL)
                m_TransactionTypes.insert(std::make_pair( (int)row[0], (wxString)row[1] ) );
            if (row[2] != NULL)
                m_StatusTypes.insert(std::make_pair( (int)row[0], (wxString)row[2] ) );
            if (row[3] != NULL)
                m_OccuranceTypes.insert(std::make_pair( (int)row[0], (wxString)row[3] ) );
        }
    }
    else
        return false;

    // load payees
    Query = wxString::Format("SELECT col_Payee FROM %s.tab_PayeeList", mmSharedDBName);
    if (this->RunQuery(Query) )
    {
        MYSQL_ROW row;
        while (row = m_pMySql->GetNextRowFromResultSet() )
        {
            m_PayeeList.Add( (wxString)row[1] );
        }
        m_PayeeList.Sort();
    }
    else
        return false;

    // load categories
    Query = wxString::Format("SELECT * FROM %s.tab_Categories", mmSharedDBName);
    if (this->RunQuery(Query) )
    {
        MYSQL_ROW row;
        while (row = m_pMySql->GetNextRowFromResultSet() )
        {
            wxString str1 = (wxString)row[1];
            wxString str2 = (wxString)row[2];
            std::map<wxString, wxArrayString>::iterator iter = m_CategoryList.find(str1);
            if (iter != m_CategoryList.end() )
            {
                if (row[2] != NULL)
                    iter->second.Add(str2);
            }
            else
            {
                wxArrayString arr;
                if (row[2] != NULL)
                    arr.Add(str2);
                m_CategoryList.insert(std::make_pair(str1, arr) );
            }
        }
        // sort all the sub categories
        std::map<wxString, wxArrayString>::iterator iter;
        for (iter = m_CategoryList.begin(); iter != m_CategoryList.end(); ++iter)
        {
            iter->second.Sort();
        }
    }
    else
        return false;

    return true;
}

bool CMainFrame::GetAvailableAccountTypes(wxArrayString& AccountTypes)
{
    AccountTypes = m_PluginManager->GetAvailableAccountPluginNames();
    if (AccountTypes.IsEmpty() )
        return false;
    else
        return true;
}

void CMainFrame::OnClose(wxCloseEvent& event)
{
#ifndef _DEBUG
    if (event.CanVeto() )
    {
/* TODO (Developer 1#3#):
Ask user if he is sure he wants to exit
if he does not then call "event.Veto()" then return.
or ask user if he wants to back up
Maybe put this in options file; 'never, always or ask' */
    }
#endif

/* FIXME (Developer 1#1#):
Exit screen is not showing the splash screen image
Maybe change this to a dialog that shows "Shutting Down" ? */

    // hide the main window
    this->Show(false);

    // show splash screen
    wxString Version = wxString::Format(_("Version %i.%i.%i"), AutoVersion::MAJOR, AutoVersion::MINOR, AutoVersion::BUILD);
    wxString Revision = wxString::Format(_("Revision %i"), AutoVersion::REVISION);
    m_pSplash = new CSplashScreen(this, 0, (mmImageDir + "splash.png"), &Version, &Revision);
    m_pSplash->SetStatusMsg(_("Shutting down...") );
    m_pSplash->Start();

    // unload plugins
    m_PluginManager.UnloadAllPlugins();

    // close MySQL Server
    if (m_pMySql)
    {
        m_pMySql->EndConnection();
        delete m_pMySql;
    }

    // clean up options
    if (mm::g_pOptions)
        delete mm::g_pOptions;

    // delete PluginManager
    if (m_pPluginManager)
        delete m_pPluginManager;

    // hide the splash screen and delete it
    m_pSplash->Stop();
    delete m_pSplash;

    // exit the main window
    this->Destroy();
}

void CMainFrame::OnMenuFileExitSelected(wxCommandEvent& event)
{
    Close();
    return;
}

void CMainFrame::OnMenuEditOptionsSelected(wxCommandEvent& event)
{
/* TODO (Developer 1#2#):
Display config options dialog */
}

void CMainFrame::OnMenuUsersAddSelected(wxCommandEvent& event)
{
/* TODO (Developer 1#3#):
Create new user menu sub routine */
}

void CMainFrame::OnMenuUsersSwitchSelected(wxCommandEvent& event)
{
/* TODO (Developer 1#3#):
switch user menu sub routine */
}

void CMainFrame::OnMenuUsersDeleteSelected(wxCommandEvent& event)
{
/* TODO (Developer 1#3#):
delete user menu sub routine */
}

void CMainFrame::OnMenuAccountsNewSelected(wxCommandEvent& event)
{
    SAccountInfo AccountInfo = { 0, "", "", "", "", "", "", 0.00, "", 0.00, "", 0.00, "" };
    m_pAccountManager->EditAccount(AccountInfo, true, true);
    return;
}

void CMainFrame::OnMenuAccountsDeleteSelected(wxCommandEvent& event)
{
/* TODO (Developer 1#3#):
Delete account menu sub routine */
}

void CMainFrame::OnMenuHelpAboutSelected(wxCommandEvent& event)
{
/* TODO (Developer 1#2#):
Add about dialog */
}

void CMainFrame::OnMenuHelpHelpSelected(wxCommandEvent& event)
{
/* TODO (Developer 1#2#):
Add help dialog */
}

void CMainFrame::OnMenuHelpLicenseSelected(wxCommandEvent& event)
{
    CLicenseDlg Dlg(this);
    Dlg.ShowModal();
    return;
}
